package com.rtsapp.server.gamelog.client.tail;

import com.rtsapp.server.logger.Logger;
import com.rtsapp.server.logger.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 某一类型日志文件的读取
 */
public class LogTail {

    private static final Logger LOG = LoggerFactory.getLogger(LogTail.class);
    /**
     * 日志过渡到第二天的时间误差, 5秒日志读取全部过渡到第二天, 5秒是留给游戏服务器的误差
     */
    private static final long LOG_ACCURACY_MILS = 5 * 1000;

    private final LogDir logDir;
    //日志类型
    private final String logType;

    //当前读取日志的时间
    private long startMils;
    private long endMils;
    private int startLine;

    //当前tail
    private Tail curTail;


    public LogTail(LogDir logDir, String logType, long startMils, int startLine) {

        this.logDir = logDir;
        this.logType = logType;

        setStartLogInfo(startMils, startLine);
    }


    /**
     * @param curMils
     * @param processor
     * @param maxLineSize
     * @return 文件是否结尾
     * @throws IOException
     */
    public boolean tail(long curMils, ILogProcessor processor, int maxLineSize) throws IOException {

        //如果tail为空, 尝试创建Tail
        createTailIfNull(curMils);

        //尝试读取N行，返回是否结尾
        if (curTail == null) {
            return true;
        }

        boolean isEnd = tail( processor, maxLineSize );


        //如果已经结尾, 且当前tail时间 在 curMils天数之前(有5秒插值), 当前tail关闭, 时间切换到下一周期
        if (isEnd && endMils <= (curMils - LOG_ACCURACY_MILS)) {
            setStartLogInfo(endMils, 0);
        }

        return isEnd;
    }

    /**
     * @param processor
     * @param maxLineSize
     * @return 是否没有读到任何数据
     * @throws IOException
     */
    private boolean tail(ILogProcessor processor, int maxLineSize) throws IOException {
        //如果tail为空, 返回
        if (curTail == null) {
            return true;
        }

        String line = null;
        for (int i = 0; i < maxLineSize; i++) {
            line =  curTail.tail();

            if (line == null) {
                return true;
            } else {
                processor.onTailLog( logType, line);
            }
        }

        return false;
    }



    private void setStartLogInfo(long startMils, int startLine) {

        this.startMils = Utils.getDayCalendar().getPeriodStartMils(startMils);
        this.endMils = Utils.getDayCalendar().getNextPeriodStartMils(this.startMils);

        this.startLine = startLine;

        //关闭tail

        close();
    }


    private void createTailIfNull(final long curMils) {

        if (curTail != null) {
            return;
        }

        final long stopMils = Utils.getDayCalendar().getPeriodStartMils(curMils);


        //创建日志, 找到大于该天的，天数最小的文件

        String logFile = null;
        if( startMils > stopMils ){
            //TODO  这里可能有bug, 只改变了startMils, endMils没有改变, 可能造成endMils不断增长,
            //startMils = stopMils;
            setStartLogInfo( stopMils, 0);
        }

        while (startMils <= stopMils) {
            //
            logFile = logDir.getLogFile(logType, startMils);
            if (logFile == null) {
                setStartLogInfo(endMils, 0);
            } else {
                break;
            }
        }


        if (logFile != null) {

            try {

                curTail = new Tail( logDir.getDir(), logFile);
                curTail.skipLines(startLine);

            } catch (FileNotFoundException e) {
                LOG.error(e);
            } catch (IOException e) {
                LOG.error(e);
            }

        }

    }


    public void close() {
        if (curTail != null) {
            try {
                curTail.close();
            } catch (IOException e) {
                LOG.error("关闭tail报错", e);
            }
            curTail = null;
        }
    }
}
